Load the data and check its structure (variables, missing values, data types)

library(tidyverse)  
── Attaching core tidyverse packages ──────────────────────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.0.4     ── Conflicts ────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(here)       
here() starts at C:/Users/Lenovo/Documents/RStudioProjects/UFO-Sightings---R-Project
library(withr)      
ufo_sightings <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2023/2023-06-20/ufo_sightings.csv')
Rows: 96429 Columns: 12── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (7): city, state, country_code, shape, reported_duration, summary, day_part
dbl  (1): duration_seconds
lgl  (1): has_images
dttm (2): reported_date_time, reported_date_time_utc
date (1): posted_date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
places <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2023/2023-06-20/places.csv')
Rows: 14417 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (6): city, alternate_city_names, state, country, country_code, timezone
dbl (4): latitude, longitude, population, elevation_m
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
day_parts_map <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2023/2023-06-20/day_parts_map.csv')
Rows: 26409 Columns: 12── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
dbl  (2): rounded_lat, rounded_long
date (1): rounded_date
time (9): astronomical_twilight_begin, nautical_twilight_begin, civil_twilight_begin, sunrise, solar_noon, sunset, civil_twilight_end, nauti...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Checking if files have been loaded correctly

head(ufo_sightings)
head(places)
head(day_parts_map)

Saving data in respective files

dir.create(here("data", "2023", "2023-06-20"), recursive = TRUE, showWarnings = FALSE)

write_csv(ufo_sightings, here("data", "2023", "2023-06-20", "ufo_sightings.csv"))
write_csv(places, here("data", "2023", "2023-06-20", "places.csv"))
write_csv(day_parts_map, here("data", "2023", "2023-06-20", "day_parts_map.csv"))

Checking missing data

glimpse(ufo_sightings)
Rows: 96,429
Columns: 12
$ reported_date_time     <dttm> 2022-08-29 06:03:00, 2022-08-20 01:51:00, 2022-08-13 05:30:00, 2022-08-06 21:00:00, 2022-08-04 07:40:00, 2022-…
$ reported_date_time_utc <dttm> 2022-08-29 06:03:00, 2022-08-20 01:51:00, 2022-08-13 05:30:00, 2022-08-06 21:00:00, 2022-08-04 07:40:00, 2022-…
$ posted_date            <date> 2022-09-09, 2022-10-08, 2022-09-09, 2022-09-09, 2022-09-09, 2022-09-09, 2022-09-09, 2022-09-09, 2022-09-09, 20…
$ city                   <chr> "Pinehurst", "Rapid City", "Cleveland", "Bloomington", "Irvine", "Moore", "Short Pump", "Norwalk", "Blayney", "…
$ state                  <chr> "NC", "MI", "OH", "IN", "CA", "OK", "VA", "CT", "New South Wales", "WY", "NH", "AZ", "FL", "OR", "Haryana", "NM…
$ country_code           <chr> "US", "US", "US", "US", "US", "US", "US", "US", "AU", "US", "US", "US", "US", "US", "IN", "US", "US", "US", "US…
$ shape                  <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ reported_duration      <chr> "15 mins\u0085", "1 minute", "2 hours", "30 seconds", "3 minutes", "10 minutes", "20 seconds", "5 minutes", "90…
$ duration_seconds       <dbl> 900, 60, 172800, 30, 180, 600, 20, 300, 120, 1800, 10, 3, 45, 60, 240, 32, 300, 600, 180, 1200, 45, 300, 180, 1…
$ summary                <chr> "Saw multi color object above horizon.", "An object in the shape of a straight line about an inch from our view…
$ has_images             <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ day_part               <chr> "night", "nautical dusk", "night", "afternoon", "night", "morning", "morning", "afternoon", NA, "astronomical d…
glimpse(places)
Rows: 14,417
Columns: 10
$ city                 <chr> "Pinehurst", "Rapid City", "Cleveland", "Bloomington", "Irvine", "Moore", "Short Pump", "Norwalk", "Blayney", "Gr…
$ alternate_city_names <chr> "Pajnkherst,bynhwrst,pynhwrst  karwlynay shmaly,Пајнхерст,بينهورست,پینهورست، کارولینای شمالی", NA, "CLE,Cleavelan…
$ state                <chr> "NC", "MI", "OH", "IN", "CA", "OK", "VA", "CT", "New South Wales", "WY", "NH", "AZ", "FL", "OR", "Haryana", "NM",…
$ country              <chr> "USA", "USA", "USA", "USA", "USA", "USA", "USA", "USA", "Australia", "USA", "USA", "USA", "USA", "USA", "India", …
$ country_code         <chr> "US", "US", "US", "US", "US", "US", "US", "US", "AU", "US", "US", "US", "US", "US", "IN", "US", "US", "US", "US",…
$ latitude             <dbl> 35.19543, 44.83445, 41.49950, 39.16533, 33.66946, 35.33951, 37.65042, 41.11760, -33.53233, 44.48912, 44.05368, 33…
$ longitude            <dbl> -79.46948, -85.28256, -81.69541, -86.52639, -117.82311, -97.48670, -77.61249, -73.40790, 149.25367, -108.05621, -…
$ timezone             <chr> "America/New_York", "America/Detroit", "America/New_York", "America/Indiana/Indianapolis", "America/Los_Angeles",…
$ population           <dbl> 15752, 1352, 388072, 84067, 256927, 60451, 24729, 88485, 3355, 1879, 2349, 1608139, 71579, 7912, 197340, 559121, …
$ elevation_m          <dbl> 160, 192, 199, 235, 17, 382, 89, 11, NA, 1156, 160, 331, 1, 157, NA, 1511, 414, 2, 393, 89, 1373, 264, 1, 89, 220…
glimpse(day_parts_map)
Rows: 26,409
Columns: 12
$ rounded_lat                 <dbl> 40, 40, 40, 40, 30, 40, 40, 40, -30, 40, 40, 30, 30, 40, 30, 40, 30, 30, 40, 30, 40, 30, 40, 30, 50, 40, 2…
$ rounded_long                <dbl> -80, -90, -80, -90, -120, -100, -80, -70, 150, -110, -70, -110, -80, -120, 80, -110, -120, -80, -100, -120…
$ rounded_date                <date> 2022-08-28, 2022-08-21, 2022-08-14, 2022-08-07, 2022-08-07, 2022-07-24, 2022-07-17, 2022-07-17, 2022-07-1…
$ astronomical_twilight_begin <time> 09:07:43, 09:38:33, 08:48:54, 09:19:00, 11:55:02, 09:39:05, 08:09:39, 07:29:37, 19:30:59, 10:01:25, 07:21…
$ nautical_twilight_begin     <time> 09:42:49, 10:14:53, 09:26:40, 09:58:23, 12:26:50, 10:22:03, 08:54:27, 08:14:25, 20:00:01, 10:47:51, 08:07…
$ civil_twilight_begin        <time> 10:16:18, 10:49:12, 10:01:56, 10:34:41, 12:57:22, 11:00:33, 09:34:01, 08:54:00, 20:29:37, 11:28:21, 08:48…
$ sunrise                     <time> 10:42:53, 11:16:15, 10:29:32, 11:02:53, 13:21:39, 11:30:01, 10:04:06, 09:24:04, 20:54:22, 11:58:55, 09:18…
$ solar_noon                  <time> 17:21:10, 18:03:05, 17:24:39, 18:05:45, 20:05:45, 18:46:32, 17:26:12, 16:46:12, 02:05:20, 19:25:26, 16:45…
$ sunset                      <time> 23:59:27, 00:49:55, 00:19:45, 01:08:37, 02:49:51, 02:03:03, 00:48:18, 00:08:20, 07:16:18, 02:51:58, 00:12…
$ civil_twilight_end          <time> 00:26:02, 01:16:58, 00:47:21, 01:36:50, 03:14:07, 02:32:31, 01:18:23, 00:38:24, 07:41:03, 03:22:32, 00:42…
$ nautical_twilight_end       <time> 00:59:31, 01:51:17, 01:22:37, 02:13:08, 03:44:39, 03:11:02, 01:57:57, 01:17:59, 08:10:40, 04:03:02, 01:23…
$ astronomical_twilight_end   <time> 01:34:37, 02:27:37, 02:00:24, 02:52:31, 04:16:27, 03:54:00, 02:42:45, 02:02:47, 08:39:42, 04:49:28, 02:09…
colSums(is.na(ufo_sightings))
    reported_date_time reported_date_time_utc            posted_date                   city                  state           country_code 
                     0                      0                      0                      0                     85                      0 
                 shape      reported_duration       duration_seconds                summary             has_images               day_part 
                  2039                      0                      0                     31                      0                   2563 
colSums(is.na(places))
                city alternate_city_names                state              country         country_code             latitude 
                   0                 2953                   32                    0                    0                    0 
           longitude             timezone           population          elevation_m 
                   0                    0                    0                 2285 
colSums(is.na(day_parts_map))
                rounded_lat                rounded_long                rounded_date astronomical_twilight_begin     nautical_twilight_begin 
                          0                           0                           0                         951                         122 
       civil_twilight_begin                     sunrise                  solar_noon                      sunset          civil_twilight_end 
                          2                           2                           0                           2                           2 
      nautical_twilight_end   astronomical_twilight_end 
                        122                         951 

Summary of the data

dim(ufo_sightings)
[1] 96429    12
summary(ufo_sightings)
 reported_date_time               reported_date_time_utc            posted_date             city              state          
 Min.   :1925-12-29 00:00:00.00   Min.   :1925-12-29 00:00:00.00   Min.   :1998-03-07   Length:96429       Length:96429      
 1st Qu.:2004-10-01 05:10:00.00   1st Qu.:2004-10-01 05:10:00.00   1st Qu.:2006-10-30   Class :character   Class :character  
 Median :2012-02-05 03:00:00.00   Median :2012-02-05 03:00:00.00   Median :2012-08-19   Mode  :character   Mode  :character  
 Mean   :2009-04-30 02:41:30.98   Mean   :2009-04-30 02:41:30.98   Mean   :2011-09-26                                        
 3rd Qu.:2016-01-25 03:30:00.00   3rd Qu.:2016-01-25 03:30:00.00   3rd Qu.:2016-07-15                                        
 Max.   :2023-05-18 19:27:00.00   Max.   :2023-05-18 19:27:00.00   Max.   :2023-05-19                                        
 country_code          shape           reported_duration  duration_seconds      summary          has_images        day_part        
 Length:96429       Length:96429       Length:96429       Min.   :0.000e+00   Length:96429       Mode :logical   Length:96429      
 Class :character   Class :character   Class :character   1st Qu.:3.000e+01   Class :character   FALSE:96429     Class :character  
 Mode  :character   Mode  :character   Mode  :character   Median :1.800e+02   Mode  :character                   Mode  :character  
                                                          Mean   :3.161e+04                                                        
                                                          3rd Qu.:6.000e+02                                                        
                                                          Max.   :1.987e+09                                                        
dim(places)
[1] 14417    10
summary(places)
     city           alternate_city_names    state             country          country_code          latitude        longitude      
 Length:14417       Length:14417         Length:14417       Length:14417       Length:14417       Min.   :-53.15   Min.   :-170.48  
 Class :character   Class :character     Class :character   Class :character   Class :character   1st Qu.: 34.99   1st Qu.: -95.46  
 Mode  :character   Mode  :character     Mode  :character   Mode  :character   Mode  :character   Median : 40.09   Median : -84.21  
                                                                                                  Mean   : 37.76   Mean   : -75.36  
                                                                                                  3rd Qu.: 42.96   3rd Qu.: -74.82  
                                                                                                  Max.   : 70.64   Max.   : 179.19  
                                                                                                                                    
   timezone           population        elevation_m    
 Length:14417       Min.   :       0   Min.   : -57.0  
 Class :character   1st Qu.:    1926   1st Qu.:  65.0  
 Mode  :character   Median :    6085   Median : 194.0  
                    Mean   :   86375   Mean   : 288.2  
                    3rd Qu.:   21993   3rd Qu.: 304.0  
                    Max.   :22315474   Max.   :3097.0  
                                       NA's   :2285    
dim(day_parts_map)
[1] 26409    12
summary(day_parts_map)
  rounded_lat      rounded_long      rounded_date        astronomical_twilight_begin nautical_twilight_begin civil_twilight_begin
 Min.   :-50.00   Min.   :-170.00   Min.   :1925-12-27   Length:26409                Length:26409            Length:26409        
 1st Qu.: 30.00   1st Qu.:-110.00   1st Qu.:1999-01-17   Class1:hms                  Class1:hms              Class1:hms          
 Median : 40.00   Median : -90.00   Median :2007-03-25   Class2:difftime             Class2:difftime         Class2:difftime     
 Mean   : 36.23   Mean   : -80.01   Mean   :2004-03-18   Mode  :numeric              Mode  :numeric          Mode  :numeric      
 3rd Qu.: 40.00   3rd Qu.: -80.00   3rd Qu.:2014-10-12                                                                           
 Max.   : 70.00   Max.   : 180.00   Max.   :2023-05-21                                                                           
   sunrise          solar_noon          sunset         civil_twilight_end nautical_twilight_end astronomical_twilight_end
 Length:26409      Length:26409      Length:26409      Length:26409       Length:26409          Length:26409             
 Class1:hms        Class1:hms        Class1:hms        Class1:hms         Class1:hms            Class1:hms               
 Class2:difftime   Class2:difftime   Class2:difftime   Class2:difftime    Class2:difftime       Class2:difftime          
 Mode  :numeric    Mode  :numeric    Mode  :numeric    Mode  :numeric     Mode  :numeric        Mode  :numeric           
                                                                                                                         
                                                                                                                         
sum(duplicated(ufo_sightings))
[1] 3

Handle missing observations (fill in or remove them), correct errors, etc.

Due to the large size of the file on which the analysis is performed, only some of the data was used for visual representation.

library(tidyverse)  
library(here)       
library(withr)
library(naniar)

UFO sightings

ufo_sightings %>% 
  dplyr::slice_sample(n = 1000) %>% 
  vis_miss(cluster = TRUE, sort_miss = TRUE)

Replacing missing data with most frequent entry and saving cleaned data

most_common_day_part <- ufo_sightings %>%
  count(day_part) %>%
  arrange(desc(n)) %>%
  slice(1) %>%
  pull(day_part)

most_common_shape <- ufo_sightings %>%
  count(shape) %>%
  arrange(desc(n)) %>%
  slice(1) %>%
  pull(shape)

# najczestrza wartosc
ufo_clean <- ufo_sightings %>%
  mutate(
    day_part = ifelse(is.na(day_part), most_common_day_part, day_part),
    shape = ifelse(is.na(shape), most_common_shape, shape)
  )

write_csv(ufo_clean, here("data", "2023", "2023-06-20", "ufo_clean.csv"))
ufo_clean %>% 
  dplyr::slice_sample(n = 1000) %>% 
  vis_miss(cluster = TRUE, sort_miss = TRUE)

Places

places %>% 
  dplyr::slice_sample(n = 1000) %>% 
  vis_miss(cluster = TRUE, sort_miss = TRUE)

Replacing missing city name with empty string, elevation with mean value and saving cleaned data

#nie mam lepszego pomysłu na uzuepłenienie niż " "
places_clean <- places %>%
  mutate(
    alternate_city_names = ifelse(is.na(alternate_city_names), " ", alternate_city_names)
  )

median_elevation <- median(places$elevation_m, na.rm = TRUE)

places_clean <- places_clean %>%
  mutate(
    elevation_m = ifelse(is.na(elevation_m), median_elevation, elevation_m)
  )

write_csv(places_clean, here("data", "2023", "2023-06-20", "places_clean.csv"))
places_clean %>% 
  dplyr::slice_sample(n = 1000) %>% 
  vis_miss(cluster = TRUE, sort_miss = TRUE)

Day parts map

day_parts_map %>% 
  dplyr::slice_sample(n = 1000) %>% 
  vis_miss(cluster = TRUE, sort_miss = TRUE)

Replacing missing data with mean value and saving cleaned data

day_parts_clean <- day_parts_map %>%
  mutate(
    astronomical_twilight_begin = ifelse(
      is.na(astronomical_twilight_begin),
      median(astronomical_twilight_begin, na.rm = TRUE),
      astronomical_twilight_begin
    ),
    astronomical_twilight_end = ifelse(
      is.na(astronomical_twilight_end),
      median(astronomical_twilight_end, na.rm = TRUE),
      astronomical_twilight_end
    )
  )

write_csv(day_parts_clean, here("data", "2023", "2023-06-20", "day_parts_clean.csv"))
day_parts_clean %>% 
  dplyr::slice_sample(n = 1000) %>% 
  vis_miss(cluster = TRUE, sort_miss = TRUE)

Adjust the data format to meet the requirements of your analysis


ufo_model_data <- ufo_clean %>%
  filter(!is.na(shape), !is.na(reported_duration), !is.na(summary))


places_model_data <- places_clean %>%
  filter(!is.na(alternate_city_names))
glimpse(ufo_model_data)
glimpse(places_model_data)
glimpse(day_parts_clean)
write_csv(ufo_model_data, here("data", "2023", "2023-06-20", "ufo_model_data.csv"))
write_csv(places_model_data, here("data", "2023", "2023-06-20", "places_model_data.csv"))

Add new columns to each dataframe

library(lubridate)
library(dplyr)
library(hms)

Dołączanie pakietu: ‘hms’

Następujący obiekt został zakryty z ‘package:lubridate’:

    hms

Adding new columns to “sightings” dataframe

ufo_model_data_mutated <- ufo_model_data %>%
  mutate(
    year = year(reported_date_time),
    month = month(reported_date_time),
    weekday = wday(reported_date_time, label = TRUE, abbr = FALSE, locale = "C"),
    is_weekend = weekday %in% c("Sat", "Sun"),
    country_upper = toupper(country_code),
    report_hour = hour(reported_date_time),
    city_state = paste(city, state, sep = ", "),
    report_delay_days = as.numeric(difftime(posted_date, as.Date(reported_date_time), units = "days"))
  )

ufo_model_data_mutated

Adding new columns to “places” dataframe

places_model_data_mutated <- places_model_data %>%
  mutate(
    city_state = paste(city, state, sep = ", "),
    is_us = country_code == "US",
    population_log = log1p(population),
    hemisphere = ifelse(latitude >= 0, "Northern", "Southern"),
    is_coastal = abs(longitude) < 80 | abs(longitude) > 120,
    pop_category = case_when(
      population < 10000 ~ "small",
      population < 100000 ~ "medium",
      TRUE ~ "large"
    ),
    elevation_category = case_when(
      is.na(elevation_m) ~ "unknown",
      elevation_m < 100 ~ "low",
      elevation_m < 500 ~ "medium",
      TRUE ~ "high"
    ),
    name_length = nchar(city),
    timezone_area = sapply(strsplit(timezone, "/"), `[`, 2)
  )

places_model_data_mutated

Adding new columns to “day parts” dataframe

day_parts_model_mutated <- day_parts_clean %>%
  mutate(
    daylight_duration = as.numeric(sunset - sunrise, units = "secs"),
    is_northern_hemisphere = rounded_lat >= 0,
    sunrise_hour = hour(sunrise),
    sunset_hour = hour(sunset),
    is_day_short = daylight_duration < 36000, # mniej niż 10h
    twilight_duration = as.numeric(astronomical_twilight_end - astronomical_twilight_begin, units = "secs"),
    is_long_twilight = twilight_duration > 5400, # 1.5h
    sunrise_minutes = hour(sunrise) * 60 + minute(sunrise),
    solar_noon_minutes = hour(solar_noon) * 60 + minute(solar_noon),
    sunset_minutes = hour(sunset) * 60 + minute(sunset)
  )

day_parts_model_mutated
library(ggplot2)
library(dplyr)
library(sf)
Linking to GEOS 3.13.0, GDAL 3.10.1, PROJ 9.5.1; sf_use_s2() is TRUE
library(rnaturalearth)
library(rnaturalearthdata)

Dołączanie pakietu: ‘rnaturalearthdata’

Następujący obiekt został zakryty z ‘package:rnaturalearth’:

    countries110

Explore data with charts

library(ggplot2)
library(dplyr)
library(sf)
library(rnaturalearth)
library(rnaturalearthdata)

##Number of sightings per day

ufo_model_data_mutated %>%
  count(date = as.Date(reported_date_time)) %>%
  ggplot(aes(x = date, y = n)) +
  geom_line(color = "steelblue") +
  labs(title = "Number of sightings per day", x = "Date", y = "Number of sightings")

Interpretation:

The chart shows daily UFO sightings over time. Sightings were rare before 1960, gradually increased through the 1990s, and peaked between 2000 and 2015. After 2015, the number of reports declined sharply. This suggests that UFO sightings may be influenced by media, public interest, or reporting practices.

Annual Trend of UFO Sightings

ufo_model_data_mutated %>%
  mutate(year = lubridate::year(reported_date_time)) %>%
  count(year) %>%
  ggplot(aes(x = year, y = n)) +
  geom_line(color = "darkblue") +
  geom_smooth(se = FALSE, color = "red", method = "loess") +
  labs(
    title = "Annual Trend of UFO Sightings",
    x = "Year",
    y = "Number of Sightings"
  ) +
  theme_minimal()

Interpretation:

The chart shows a clear rise in UFO sightings from the 1980s to around 2012, with a peak near 2014. After that, there’s a sharp decline in reports. The red loess curve highlights a long-term upward trend followed by a recent downward shift. This may reflect changes in reporting behavior, public interest, or data availability over time.

##Number of sightings depending on the day of the week

ufo_model_data_mutated %>%
  count(weekday) %>%
  ggplot(aes(x = weekday, y = n)) +
  geom_col(fill = "orange") +
  labs(title = "Sightings depending on the day of the week", x = "Day of the week", y = "Number of sightings")

Interpretation:

The number of UFO sightings varies by day of the week. The highest counts occur on Saturdays and Sundays, while Tuesdays have the fewest reports. This suggests people are more likely to notice and report sightings during weekends, possibly due to having more free time or being outdoors more often.

Hourly distribution of sightings

ufo_model_data_mutated %>%
  mutate(hour = hour(reported_date_time)) %>%
  count(hour) %>%
  ggplot(aes(x = hour, y = n)) +
  geom_col(fill = "purple") +
  labs(title = "Hourly distribution of sightings", x = "Hour of the day", y = "Number of sightings")

Interpretation:

UFO sightings are most frequently reported between 8 PM and 3 AM, peaking around 2 AM. Sightings are least common during midday hours. This pattern suggests that sightings are more likely to occur—or at least be noticed and reported—at night, when the sky is dark and unusual lights are more visible.

Heatmap: day of the week vs hour of the day

ufo_model_data_mutated %>%
  mutate(
    hour = hour(reported_date_time),
    weekday = fct_relevel(weekday, c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"))
  ) %>%
  count(weekday, hour) %>%
  ggplot(aes(x = hour, y = weekday, fill = n)) +
  geom_tile(color = "white") +
  scale_fill_viridis_c() +
  labs(title = "Heatmap: day of the week vs hour of the day", x = "Hour of the day", y = "Day of the week", fill = "Number of sightings")

Interpretation:

The heatmap shows the distribution of UFO sightings by hour of the day and day of the week. Most sightings occur after midnight on Sunday, peaking between 1–3 AM. Other late-night hours, especially on weekends, also show elevated counts. This pattern reinforces that sightings are more frequent during late-night weekend hours, when people are likely to be awake and outdoors in dark conditions.

Sightins with images vs no image

ufo_model_data_mutated %>%
  mutate(image_status = ifelse(has_images, "Has an image", "Has no image")) %>%
  count(image_status) %>%
  ggplot(aes(x = "", y = n, fill = image_status)) +
  geom_col(width = 1) +
  coord_polar(theta = "y") +
  labs(title = "Sightins with images vs no image", fill = "Image existence") +
  theme_void() +
  scale_fill_manual(values = c("Has an image" = "#66BB6A", "Has no image" = "#EF5350"))

Interpretation:

The chart shows that almost all UFO sightings lack images. Sightings with images are extremely rare, suggesting that reports are usually text-based or anecdotal. This indicates a strong reliance on witness testimony rather than visual evidence in the dataset.

Making sure if above piechart is correct

sum(ufo_model_data_mutated$has_images != FALSE, na.rm = TRUE)

Number of sightings per shape

ufo_model_data_mutated %>%
  count(shape) %>%
  ggplot(aes(x = reorder(shape, n), y = n)) +
  geom_col(fill = "skyblue") +
  coord_flip() +
  labs(title = "Number of sightings per shape", x = "Shape", y = "Number of sightings")

Interpretation:

The most commonly reported UFO shapes are light, circle, and triangle. Unusual shapes like cube, star, and cross are very rare. This suggests that most sightings describe simple or glowing forms, possibly influenced by visibility, perception, or common cultural imagery.

Number of sightings per country

ufo_model_data_mutated %>%
  count(country_code) %>%
  filter(n >= 100) %>%
  ggplot(aes(x = reorder(country_code, n), y = n)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(
    title = "Number of sightings per country",
    x = "Country code",
    y = "Number of sightings"
  ) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Interpretation:

The vast majority of UFO sightings come from the United States, with over 80,000 reports. Other countries like Canada and Great Britain have significantly fewer sightings. This suggests that the dataset is strongly US-centric, possibly due to better reporting infrastructure, public interest, or data source bias.

Density map of sightings

world <- ne_countries(scale = "medium", returnclass = "sf")

places_clean %>%
  filter(!is.na(latitude), !is.na(longitude)) %>%
  mutate(
    pop_category = case_when(
      population < 10000  ~ "small",
      population < 100000 ~ "medium",
      TRUE                ~ "large"
    )
  ) %>%
  ggplot() +
  geom_sf(data = world, fill = "lightgray", color = "black") +  # Dodajemy mapę
  geom_point(aes(
    x = longitude, y = latitude,
    size = population, color = pop_category
  ), alpha = 0.6) +
  scale_size(range = c(1, 6), guide = "none") +
  labs(
    title = "Cities with UFO sightings",
    subtitle = "Point size ~ population, color ~ population category",
    x = "Latitude",
    y = "Altitude",
    color = "Population category"
  ) +
  theme_minimal()

Interpretation:

Sightings are most densely clustered in North America and Europe, especially in large urban areas. This suggests that population density and infrastructure may influence reporting frequency. Other regions show fewer reports, which could reflect lower reporting access or less data availability.

UFO Sightings by City Population Category

ufo_model_data_mutated %>%
  left_join(places_model_data_mutated %>% select(city_state, pop_category), by = "city_state") %>%
  count(pop_category) %>%
  ggplot(aes(x = pop_category, y = n, fill = pop_category)) +
  geom_col(show.legend = FALSE) +
  labs(
    title = "UFO Sightings by City Population Category",
    x = "Population Category",
    y = "Number of Sightings"
  ) +
  scale_fill_manual(values = c("small" = "#91bfdb", "medium" = "#fdae61", "large" = "#d73027")) +
  theme_minimal()
Ostrzeżenie: Detected an unexpected many-to-many relationship between `x` and `y`.

Interpretation:

The chart shows that most UFO sightings come from medium-sized cities, followed by large cities, with small towns reporting the fewest. This suggests that mid-sized urban areas may offer a balance of visibility, outdoor activity, and public engagement conducive to sightings. It also reflects where people live and are most likely to report unusual events.

LS0tDQp0aXRsZTogIkV4cGxvcmF0b3J5IERhdGEgQW5hbGFzeXMgd2l0aCBVRk8gc2lnbmFscyBkYXRhc2V0Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyBMb2FkIHRoZSBkYXRhIGFuZCBjaGVjayBpdHMgc3RydWN0dXJlICh2YXJpYWJsZXMsIG1pc3NpbmcgdmFsdWVzLCBkYXRhIHR5cGVzKQ0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKSAgDQpsaWJyYXJ5KGhlcmUpICAgICAgIA0KbGlicmFyeSh3aXRocikgICAgICANCmBgYA0KDQpgYGB7cn0NCnVmb19zaWdodGluZ3MgPC0gcmVhZHI6OnJlYWRfY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L21haW4vZGF0YS8yMDIzLzIwMjMtMDYtMjAvdWZvX3NpZ2h0aW5ncy5jc3YnKQ0KcGxhY2VzIDwtIHJlYWRyOjpyZWFkX2NzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9tYWluL2RhdGEvMjAyMy8yMDIzLTA2LTIwL3BsYWNlcy5jc3YnKQ0KZGF5X3BhcnRzX21hcCA8LSByZWFkcjo6cmVhZF9jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9yZm9yZGF0YXNjaWVuY2UvdGlkeXR1ZXNkYXkvbWFpbi9kYXRhLzIwMjMvMjAyMy0wNi0yMC9kYXlfcGFydHNfbWFwLmNzdicpDQoNCmBgYA0KDQpDaGVja2luZyBpZiBmaWxlcyBoYXZlIGJlZW4gbG9hZGVkIGNvcnJlY3RseQ0KDQpgYGB7cn0NCmhlYWQodWZvX3NpZ2h0aW5ncykNCmhlYWQocGxhY2VzKQ0KaGVhZChkYXlfcGFydHNfbWFwKQ0KYGBgDQoNClNhdmluZyBkYXRhIGluIHJlc3BlY3RpdmUgZmlsZXMNCg0KYGBge3J9DQpkaXIuY3JlYXRlKGhlcmUoImRhdGEiLCAiMjAyMyIsICIyMDIzLTA2LTIwIiksIHJlY3Vyc2l2ZSA9IFRSVUUsIHNob3dXYXJuaW5ncyA9IEZBTFNFKQ0KDQp3cml0ZV9jc3YodWZvX3NpZ2h0aW5ncywgaGVyZSgiZGF0YSIsICIyMDIzIiwgIjIwMjMtMDYtMjAiLCAidWZvX3NpZ2h0aW5ncy5jc3YiKSkNCndyaXRlX2NzdihwbGFjZXMsIGhlcmUoImRhdGEiLCAiMjAyMyIsICIyMDIzLTA2LTIwIiwgInBsYWNlcy5jc3YiKSkNCndyaXRlX2NzdihkYXlfcGFydHNfbWFwLCBoZXJlKCJkYXRhIiwgIjIwMjMiLCAiMjAyMy0wNi0yMCIsICJkYXlfcGFydHNfbWFwLmNzdiIpKQ0KYGBgDQoNCkNoZWNraW5nIG1pc3NpbmcgZGF0YQ0KDQpgYGB7cn0NCmdsaW1wc2UodWZvX3NpZ2h0aW5ncykNCmdsaW1wc2UocGxhY2VzKQ0KZ2xpbXBzZShkYXlfcGFydHNfbWFwKQ0KYGBgDQoNCmBgYHtyfQ0KY29sU3Vtcyhpcy5uYSh1Zm9fc2lnaHRpbmdzKSkNCmBgYA0KDQpgYGB7cn0NCmNvbFN1bXMoaXMubmEocGxhY2VzKSkNCmBgYA0KDQpgYGB7cn0NCmNvbFN1bXMoaXMubmEoZGF5X3BhcnRzX21hcCkpDQpgYGANCg0KU3VtbWFyeSBvZiB0aGUgZGF0YQ0KDQpgYGB7cn0NCmRpbSh1Zm9fc2lnaHRpbmdzKQ0Kc3VtbWFyeSh1Zm9fc2lnaHRpbmdzKQ0KYGBgDQoNCmBgYHtyfQ0KZGltKHBsYWNlcykNCnN1bW1hcnkocGxhY2VzKQ0KYGBgDQoNCmBgYHtyfQ0KZGltKGRheV9wYXJ0c19tYXApDQpzdW1tYXJ5KGRheV9wYXJ0c19tYXApDQpgYGANCg0KYGBge3J9DQpzdW0oZHVwbGljYXRlZCh1Zm9fc2lnaHRpbmdzKSkNCmBgYA0KDQojIEhhbmRsZSBtaXNzaW5nIG9ic2VydmF0aW9ucyAoZmlsbCBpbiBvciByZW1vdmUgdGhlbSksIGNvcnJlY3QgZXJyb3JzLCBldGMuDQoNCkR1ZSB0byB0aGUgbGFyZ2Ugc2l6ZSBvZiB0aGUgZmlsZSBvbiB3aGljaCB0aGUgYW5hbHlzaXMgaXMgcGVyZm9ybWVkLCBvbmx5IHNvbWUgb2YgdGhlIGRhdGEgd2FzIHVzZWQgZm9yIHZpc3VhbCByZXByZXNlbnRhdGlvbi4NCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkgIA0KbGlicmFyeShoZXJlKSAgICAgICANCmxpYnJhcnkod2l0aHIpDQpsaWJyYXJ5KG5hbmlhcikNCmBgYA0KDQojIyBVRk8gc2lnaHRpbmdzDQoNCmBgYHtyfQ0KdWZvX3NpZ2h0aW5ncyAlPiUgDQogIGRwbHlyOjpzbGljZV9zYW1wbGUobiA9IDEwMDApICU+JSANCiAgdmlzX21pc3MoY2x1c3RlciA9IFRSVUUsIHNvcnRfbWlzcyA9IFRSVUUpDQpgYGANCg0KUmVwbGFjaW5nIG1pc3NpbmcgZGF0YSB3aXRoIG1vc3QgZnJlcXVlbnQgZW50cnkgYW5kIHNhdmluZyBjbGVhbmVkIGRhdGENCg0KYGBge3J9DQptb3N0X2NvbW1vbl9kYXlfcGFydCA8LSB1Zm9fc2lnaHRpbmdzICU+JQ0KICBjb3VudChkYXlfcGFydCkgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lDQogIHNsaWNlKDEpICU+JQ0KICBwdWxsKGRheV9wYXJ0KQ0KDQptb3N0X2NvbW1vbl9zaGFwZSA8LSB1Zm9fc2lnaHRpbmdzICU+JQ0KICBjb3VudChzaGFwZSkgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lDQogIHNsaWNlKDEpICU+JQ0KICBwdWxsKHNoYXBlKQ0KDQp1Zm9fY2xlYW4gPC0gdWZvX3NpZ2h0aW5ncyAlPiUNCiAgbXV0YXRlKA0KICAgIGRheV9wYXJ0ID0gaWZlbHNlKGlzLm5hKGRheV9wYXJ0KSwgbW9zdF9jb21tb25fZGF5X3BhcnQsIGRheV9wYXJ0KSwNCiAgICBzaGFwZSA9IGlmZWxzZShpcy5uYShzaGFwZSksIG1vc3RfY29tbW9uX3NoYXBlLCBzaGFwZSkNCiAgKQ0KDQp3cml0ZV9jc3YodWZvX2NsZWFuLCBoZXJlKCJkYXRhIiwgIjIwMjMiLCAiMjAyMy0wNi0yMCIsICJ1Zm9fY2xlYW4uY3N2IikpDQoNCmBgYA0KDQpgYGB7cn0NCnVmb19jbGVhbiAlPiUgDQogIGRwbHlyOjpzbGljZV9zYW1wbGUobiA9IDEwMDApICU+JSANCiAgdmlzX21pc3MoY2x1c3RlciA9IFRSVUUsIHNvcnRfbWlzcyA9IFRSVUUpDQpgYGANCg0KIyMgUGxhY2VzDQoNCmBgYHtyfQ0KcGxhY2VzICU+JSANCiAgZHBseXI6OnNsaWNlX3NhbXBsZShuID0gMTAwMCkgJT4lIA0KICB2aXNfbWlzcyhjbHVzdGVyID0gVFJVRSwgc29ydF9taXNzID0gVFJVRSkNCmBgYA0KDQpSZXBsYWNpbmcgbWlzc2luZyBjaXR5IG5hbWUgd2l0aCBlbXB0eSBzdHJpbmcsIGVsZXZhdGlvbiB3aXRoIG1lYW4gdmFsdWUgYW5kIHNhdmluZyBjbGVhbmVkIGRhdGENCg0KYGBge3J9DQpwbGFjZXNfY2xlYW4gPC0gcGxhY2VzICU+JQ0KICBtdXRhdGUoDQogICAgYWx0ZXJuYXRlX2NpdHlfbmFtZXMgPSBpZmVsc2UoaXMubmEoYWx0ZXJuYXRlX2NpdHlfbmFtZXMpLCAiICIsIGFsdGVybmF0ZV9jaXR5X25hbWVzKQ0KICApDQoNCm1lZGlhbl9lbGV2YXRpb24gPC0gbWVkaWFuKHBsYWNlcyRlbGV2YXRpb25fbSwgbmEucm0gPSBUUlVFKQ0KDQpwbGFjZXNfY2xlYW4gPC0gcGxhY2VzX2NsZWFuICU+JQ0KICBtdXRhdGUoDQogICAgZWxldmF0aW9uX20gPSBpZmVsc2UoaXMubmEoZWxldmF0aW9uX20pLCBtZWRpYW5fZWxldmF0aW9uLCBlbGV2YXRpb25fbSkNCiAgKQ0KDQp3cml0ZV9jc3YocGxhY2VzX2NsZWFuLCBoZXJlKCJkYXRhIiwgIjIwMjMiLCAiMjAyMy0wNi0yMCIsICJwbGFjZXNfY2xlYW4uY3N2IikpDQpgYGANCg0KYGBge3J9DQpwbGFjZXNfY2xlYW4gJT4lIA0KICBkcGx5cjo6c2xpY2Vfc2FtcGxlKG4gPSAxMDAwKSAlPiUgDQogIHZpc19taXNzKGNsdXN0ZXIgPSBUUlVFLCBzb3J0X21pc3MgPSBUUlVFKQ0KYGBgDQoNCiMjIERheSBwYXJ0cyBtYXANCg0KYGBge3J9DQpkYXlfcGFydHNfbWFwICU+JSANCiAgZHBseXI6OnNsaWNlX3NhbXBsZShuID0gMTAwMCkgJT4lIA0KICB2aXNfbWlzcyhjbHVzdGVyID0gVFJVRSwgc29ydF9taXNzID0gVFJVRSkNCmBgYA0KDQpSZXBsYWNpbmcgbWlzc2luZyBkYXRhIHdpdGggbWVhbiB2YWx1ZSBhbmQgc2F2aW5nIGNsZWFuZWQgZGF0YQ0KDQpgYGB7cn0NCmRheV9wYXJ0c19jbGVhbiA8LSBkYXlfcGFydHNfbWFwICU+JQ0KICBtdXRhdGUoDQogICAgYXN0cm9ub21pY2FsX3R3aWxpZ2h0X2JlZ2luID0gaWZlbHNlKA0KICAgICAgaXMubmEoYXN0cm9ub21pY2FsX3R3aWxpZ2h0X2JlZ2luKSwNCiAgICAgIG1lZGlhbihhc3Ryb25vbWljYWxfdHdpbGlnaHRfYmVnaW4sIG5hLnJtID0gVFJVRSksDQogICAgICBhc3Ryb25vbWljYWxfdHdpbGlnaHRfYmVnaW4NCiAgICApLA0KICAgIGFzdHJvbm9taWNhbF90d2lsaWdodF9lbmQgPSBpZmVsc2UoDQogICAgICBpcy5uYShhc3Ryb25vbWljYWxfdHdpbGlnaHRfZW5kKSwNCiAgICAgIG1lZGlhbihhc3Ryb25vbWljYWxfdHdpbGlnaHRfZW5kLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgYXN0cm9ub21pY2FsX3R3aWxpZ2h0X2VuZA0KICAgICkNCiAgKQ0KDQp3cml0ZV9jc3YoZGF5X3BhcnRzX2NsZWFuLCBoZXJlKCJkYXRhIiwgIjIwMjMiLCAiMjAyMy0wNi0yMCIsICJkYXlfcGFydHNfY2xlYW4uY3N2IikpDQpgYGANCg0KYGBge3J9DQpkYXlfcGFydHNfY2xlYW4gJT4lIA0KICBkcGx5cjo6c2xpY2Vfc2FtcGxlKG4gPSAxMDAwKSAlPiUgDQogIHZpc19taXNzKGNsdXN0ZXIgPSBUUlVFLCBzb3J0X21pc3MgPSBUUlVFKQ0KYGBgDQoNCiMgQWRqdXN0IHRoZSBkYXRhIGZvcm1hdCB0byBtZWV0IHRoZSByZXF1aXJlbWVudHMgb2YgeW91ciBhbmFseXNpcw0KDQpgYGB7cn0NCg0KdWZvX21vZGVsX2RhdGEgPC0gdWZvX2NsZWFuICU+JQ0KICBmaWx0ZXIoIWlzLm5hKHNoYXBlKSwgIWlzLm5hKHJlcG9ydGVkX2R1cmF0aW9uKSwgIWlzLm5hKHN1bW1hcnkpKQ0KDQoNCnBsYWNlc19tb2RlbF9kYXRhIDwtIHBsYWNlc19jbGVhbiAlPiUNCiAgZmlsdGVyKCFpcy5uYShhbHRlcm5hdGVfY2l0eV9uYW1lcykpDQoNCmBgYA0KDQpgYGB7cn0NCmdsaW1wc2UodWZvX21vZGVsX2RhdGEpDQpnbGltcHNlKHBsYWNlc19tb2RlbF9kYXRhKQ0KZ2xpbXBzZShkYXlfcGFydHNfY2xlYW4pDQpgYGANCg0KYGBge3J9DQp3cml0ZV9jc3YodWZvX21vZGVsX2RhdGEsIGhlcmUoImRhdGEiLCAiMjAyMyIsICIyMDIzLTA2LTIwIiwgInVmb19tb2RlbF9kYXRhLmNzdiIpKQ0Kd3JpdGVfY3N2KHBsYWNlc19tb2RlbF9kYXRhLCBoZXJlKCJkYXRhIiwgIjIwMjMiLCAiMjAyMy0wNi0yMCIsICJwbGFjZXNfbW9kZWxfZGF0YS5jc3YiKSkNCmBgYA0KDQojIEFkZCBuZXcgY29sdW1ucyB0byBlYWNoIGRhdGFmcmFtZQ0KDQpgYGB7cn0NCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoaG1zKQ0KYGBgDQoNCkFkZGluZyBuZXcgY29sdW1ucyB0byAic2lnaHRpbmdzIiBkYXRhZnJhbWUNCg0KYGBge3J9DQp1Zm9fbW9kZWxfZGF0YV9tdXRhdGVkIDwtIHVmb19tb2RlbF9kYXRhICU+JQ0KICBtdXRhdGUoDQogICAgeWVhciA9IHllYXIocmVwb3J0ZWRfZGF0ZV90aW1lKSwNCiAgICBtb250aCA9IG1vbnRoKHJlcG9ydGVkX2RhdGVfdGltZSksDQogICAgd2Vla2RheSA9IHdkYXkocmVwb3J0ZWRfZGF0ZV90aW1lLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBGQUxTRSwgbG9jYWxlID0gIkMiKSwNCiAgICBpc193ZWVrZW5kID0gd2Vla2RheSAlaW4lIGMoIlNhdCIsICJTdW4iKSwNCiAgICBjb3VudHJ5X3VwcGVyID0gdG91cHBlcihjb3VudHJ5X2NvZGUpLA0KICAgIHJlcG9ydF9ob3VyID0gaG91cihyZXBvcnRlZF9kYXRlX3RpbWUpLA0KICAgIGNpdHlfc3RhdGUgPSBwYXN0ZShjaXR5LCBzdGF0ZSwgc2VwID0gIiwgIiksDQogICAgcmVwb3J0X2RlbGF5X2RheXMgPSBhcy5udW1lcmljKGRpZmZ0aW1lKHBvc3RlZF9kYXRlLCBhcy5EYXRlKHJlcG9ydGVkX2RhdGVfdGltZSksIHVuaXRzID0gImRheXMiKSkNCiAgKQ0KDQp1Zm9fbW9kZWxfZGF0YV9tdXRhdGVkDQpgYGANCg0KLSAgIGB5ZWFyYDogRXh0cmFjdHMgdGhlIHllYXIgZnJvbSB0aGUgYHJlcG9ydGVkX2RhdGVfdGltZWAuDQotICAgYG1vbnRoYDogRXh0cmFjdHMgdGhlIG1vbnRoICgx4oCTMTIpIGZyb20gdGhlIHJlcG9ydCB0aW1lLXN0YW1wLg0KLSAgIGB3ZWVrZGF5YDogUmV0dXJucyB0aGUgd2Vla2RheSBuYW1lIGZyb20gdGhlIGRhdGUuDQotICAgYGlzX3dlZWtlbmRgOiBMb2dpY2FsIGNvbHVtbjogYFRSVUVgIGlmIHRoZSBkYXkgaXMgU2F0dXJkYXkgb3IgU3VuZGF5LCBgRkFMU0VgIG90aGVyd2lzZS4NCi0gICBgY291bnRyeV91cHBlcmA6IENvbnZlcnRzIHRoZSBgY291bnRyeV9jb2RlYCB0byB1cHBlcmNhc2UuDQotICAgYHJlcG9ydF9ob3VyYDogRXh0cmFjdHMgdGhlIGhvdXIgKDDigJMyMykgZnJvbSB0aGUgcmVwb3J0IHRpbWUtc3RhbXAuDQotICAgYGNpdHlfc3RhdGVgOiBDb25jYXRlbmF0ZXMgYGNpdHlgIGFuZCBgc3RhdGVgIGludG8gYSBzaW5nbGUgc3RyaW5nLg0KLSAgIGByZXBvcnRfZGVsYXlfZGF5c2A6IENhbGN1bGF0ZXMgdGhlIGRlbGF5IGluIGRheXMgYmV0d2VlbiB3aGVuIHRoZSBldmVudCB3YXMgcmVwb3J0ZWQgYW5kIHdoZW4gaXQgd2FzIHBvc3RlZC4NCg0KQWRkaW5nIG5ldyBjb2x1bW5zIHRvICJwbGFjZXMiIGRhdGFmcmFtZQ0KDQpgYGB7cn0NCnBsYWNlc19tb2RlbF9kYXRhX211dGF0ZWQgPC0gcGxhY2VzX21vZGVsX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBjaXR5X3N0YXRlID0gcGFzdGUoY2l0eSwgc3RhdGUsIHNlcCA9ICIsICIpLA0KICAgIGlzX3VzID0gY291bnRyeV9jb2RlID09ICJVUyIsDQogICAgcG9wdWxhdGlvbl9sb2cgPSBsb2cxcChwb3B1bGF0aW9uKSwNCiAgICBoZW1pc3BoZXJlID0gaWZlbHNlKGxhdGl0dWRlID49IDAsICJOb3J0aGVybiIsICJTb3V0aGVybiIpLA0KICAgIGlzX2NvYXN0YWwgPSBhYnMobG9uZ2l0dWRlKSA8IDgwIHwgYWJzKGxvbmdpdHVkZSkgPiAxMjAsDQogICAgcG9wX2NhdGVnb3J5ID0gY2FzZV93aGVuKA0KICAgICAgcG9wdWxhdGlvbiA8IDEwMDAwIH4gInNtYWxsIiwNCiAgICAgIHBvcHVsYXRpb24gPCAxMDAwMDAgfiAibWVkaXVtIiwNCiAgICAgIFRSVUUgfiAibGFyZ2UiDQogICAgKSwNCiAgICBlbGV2YXRpb25fY2F0ZWdvcnkgPSBjYXNlX3doZW4oDQogICAgICBpcy5uYShlbGV2YXRpb25fbSkgfiAidW5rbm93biIsDQogICAgICBlbGV2YXRpb25fbSA8IDEwMCB+ICJsb3ciLA0KICAgICAgZWxldmF0aW9uX20gPCA1MDAgfiAibWVkaXVtIiwNCiAgICAgIFRSVUUgfiAiaGlnaCINCiAgICApLA0KICAgIG5hbWVfbGVuZ3RoID0gbmNoYXIoY2l0eSksDQogICAgdGltZXpvbmVfYXJlYSA9IHNhcHBseShzdHJzcGxpdCh0aW1lem9uZSwgIi8iKSwgYFtgLCAyKQ0KICApDQoNCnBsYWNlc19tb2RlbF9kYXRhX211dGF0ZWQNCmBgYA0KDQotICAgYGNpdHlfc3RhdGVgOiBDb21iaW5lcyBgY2l0eWAgYW5kIGBzdGF0ZWAgaW50byBhIHNpbmdsZSBzdHJpbmcuDQotICAgYGlzX3VzYDogTG9naWNhbCB2YWx1ZTogYFRSVUVgIGlmIHRoZSBsb2NhdGlvbiBpcyBpbiB0aGUgVW5pdGVkIFN0YXRlcyBlbHNlIGBGQUxTRWAuDQotICAgYHBvcHVsYXRpb25fbG9nYDogTG9nLXRyYW5zZm9ybWVkIHBvcHVsYXRpb24uDQotICAgYGhlbWlzcGhlcmVgOiBgIk5vcnRoZXJuImAgaWYgbGF0aXR1ZGUgaXMg4omlIDAsIGAiU291dGhlcm4iYCBvdGhlcndpc2UuDQotICAgYGlzX2NvYXN0YWxgOiBMb2dpY2FsOiBgVFJVRWAgaWYgbG9uZ2l0dWRlIGlzIG91dHNpZGUgdGhlIHJhbmdlIFs4MCwgMTIwXSBpbiBhYnNvbHV0ZSB2YWx1ZSDigJQgYSByb3VnaCBjb2FzdGFsIHByb3h5Lg0KLSAgIGBwb3BfY2F0ZWdvcnlgOiBDYXRlZ29yaXplcyBwbGFjZXMgYmFzZWQgb24gcG9wdWxhdGlvbjogYCJzbWFsbCJgLCBgIm1lZGl1bSJgLCBvciBgImxhcmdlImAuDQotICAgYGVsZXZhdGlvbl9jYXRlZ29yeWA6IENsYXNzaWZpZXMgZWxldmF0aW9uOiBgImxvdyJgIChcPDEwMCBtKSwgYCJtZWRpdW0iYCAoXDw1MDAgbSksIGAiaGlnaCJgICjiiaU1MDAgbSksIG9yIGAidW5rbm93biJgIGlmIE5BLg0KLSAgIGBuYW1lX2xlbmd0aGA6IFRoZSBudW1iZXIgb2YgY2hhcmFjdGVycyBpbiB0aGUgY2l0eSBuYW1lLg0KLSAgIGB0aW1lem9uZV9hcmVhYDogRXh0cmFjdHMgdGhlIHNlY29uZCBwYXJ0IG9mIHRoZSB0aW1lem9uZSBzdHJpbmcuDQoNCkFkZGluZyBuZXcgY29sdW1ucyB0byAiZGF5IHBhcnRzIiBkYXRhZnJhbWUNCg0KYGBge3J9DQpkYXlfcGFydHNfbW9kZWxfbXV0YXRlZCA8LSBkYXlfcGFydHNfY2xlYW4gJT4lDQogIG11dGF0ZSgNCiAgICBkYXlsaWdodF9kdXJhdGlvbiA9IGFzLm51bWVyaWMoc3Vuc2V0IC0gc3VucmlzZSwgdW5pdHMgPSAic2VjcyIpLA0KICAgIGlzX25vcnRoZXJuX2hlbWlzcGhlcmUgPSByb3VuZGVkX2xhdCA+PSAwLA0KICAgIHN1bnJpc2VfaG91ciA9IGhvdXIoc3VucmlzZSksDQogICAgc3Vuc2V0X2hvdXIgPSBob3VyKHN1bnNldCksDQogICAgaXNfZGF5X3Nob3J0ID0gZGF5bGlnaHRfZHVyYXRpb24gPCAzNjAwMCwgIyBtbmllaiBuacW8IDEwaA0KICAgIHR3aWxpZ2h0X2R1cmF0aW9uID0gYXMubnVtZXJpYyhhc3Ryb25vbWljYWxfdHdpbGlnaHRfZW5kIC0gYXN0cm9ub21pY2FsX3R3aWxpZ2h0X2JlZ2luLCB1bml0cyA9ICJzZWNzIiksDQogICAgaXNfbG9uZ190d2lsaWdodCA9IHR3aWxpZ2h0X2R1cmF0aW9uID4gNTQwMCwgIyAxLjVoDQogICAgc3VucmlzZV9taW51dGVzID0gaG91cihzdW5yaXNlKSAqIDYwICsgbWludXRlKHN1bnJpc2UpLA0KICAgIHNvbGFyX25vb25fbWludXRlcyA9IGhvdXIoc29sYXJfbm9vbikgKiA2MCArIG1pbnV0ZShzb2xhcl9ub29uKSwNCiAgICBzdW5zZXRfbWludXRlcyA9IGhvdXIoc3Vuc2V0KSAqIDYwICsgbWludXRlKHN1bnNldCkNCiAgKQ0KDQpkYXlfcGFydHNfbW9kZWxfbXV0YXRlZA0KYGBgDQoNCi0gICBgZGF5bGlnaHRfZHVyYXRpb25gOiBUaGUgbGVuZ3RoIG9mIHRoZSBkYXkgaW4gc2Vjb25kcyDigJQgZGlmZmVyZW5jZSBiZXR3ZWVuIGBzdW5zZXRgIGFuZCBgc3VucmlzZWAuDQotICAgYGlzX25vcnRoZXJuX2hlbWlzcGhlcmVgOiBMb2dpY2FsOiBgVFJVRWAgaWYgdGhlIGxvY2F0aW9uIGlzIGluIHRoZSBOb3J0aGVybiBIZW1pc3BoZXJlLg0KLSAgIGBzdW5yaXNlX2hvdXJgOiBUaGUgaG91ciAoMOKAkzIzKSB3aGVuIHRoZSBzdW4gcmlzZXMuDQotICAgYHN1bnNldF9ob3VyYDogVGhlIGhvdXIgKDDigJMyMykgd2hlbiB0aGUgc3VuIHNldHMuDQotICAgYGlzX2RheV9zaG9ydGA6IExvZ2ljYWw6IGBUUlVFYCBpZiB0aGUgZGF5IGlzIHNob3J0ZXIgdGhhbiAxMCBob3Vycw0KLSAgIGB0d2lsaWdodF9kdXJhdGlvbmA6IER1cmF0aW9uIG9mIGFzdHJvbm9taWNhbCB0d2lsaWdodCBpbiBzZWNvbmRzIOKAlCB0aW1lIGJldHdlZW4gYGFzdHJvbm9taWNhbF90d2lsaWdodF9iZWdpbmAgYW5kIGBlbmRgLg0KLSAgIGBpc19sb25nX3R3aWxpZ2h0YDogTG9naWNhbDogYFRSVUVgIGlmIHR3aWxpZ2h0IGR1cmF0aW9uIGlzIGxvbmdlciB0aGFuIDEuNSBob3Vycw0KLSAgIGBzdW5yaXNlX21pbnV0ZXNgOiBTdW5yaXNlIHRpbWUgaW4gdG90YWwgbWludXRlcyBmcm9tIG1pZG5pZ2h0Lg0KLSAgIGBzb2xhcl9ub29uX21pbnV0ZXNgOiBTb2xhciBub29uIHRpbWUgaW4gbWludXRlcyBmcm9tIG1pZG5pZ2h0Lg0KLSAgIGBzdW5zZXRfbWludXRlc2A6IFN1bnNldCB0aW1lIGluIG1pbnV0ZXMgZnJvbSBtaWRuaWdodC4NCg0KYGBge3J9DQpnbGltcHNlKHVmb19tb2RlbF9kYXRhX211dGF0ZWQpDQpnbGltcHNlKHBsYWNlc19tb2RlbF9kYXRhX211dGF0ZWQpDQpnbGltcHNlKGRheV9wYXJ0c19jbGVhbikNCmBgYA0KDQojIEV4cGxvcmUgZGF0YSB3aXRoIGNoYXJ0cw0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShybmF0dXJhbGVhcnRoKQ0KbGlicmFyeShybmF0dXJhbGVhcnRoZGF0YSkNCmBgYA0KDQojI051bWJlciBvZiBzaWdodGluZ3MgcGVyIGRheQ0KDQpgYGB7cn0NCnVmb19tb2RlbF9kYXRhX211dGF0ZWQgJT4lDQogIGNvdW50KGRhdGUgPSBhcy5EYXRlKHJlcG9ydGVkX2RhdGVfdGltZSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gbikpICsNCiAgZ2VvbV9saW5lKGNvbG9yID0gInN0ZWVsYmx1ZSIpICsNCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2Ygc2lnaHRpbmdzIHBlciBkYXkiLCB4ID0gIkRhdGUiLCB5ID0gIk51bWJlciBvZiBzaWdodGluZ3MiKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXRpb246KioNCg0KVGhlIGNoYXJ0IHNob3dzIGRhaWx5IFVGTyBzaWdodGluZ3Mgb3ZlciB0aW1lLiBTaWdodGluZ3Mgd2VyZSByYXJlIGJlZm9yZSAxOTYwLCBncmFkdWFsbHkgaW5jcmVhc2VkIHRocm91Z2ggdGhlIDE5OTBzLCBhbmQgcGVha2VkIGJldHdlZW4gMjAwMCBhbmQgMjAxNS4gQWZ0ZXIgMjAxNSwgdGhlIG51bWJlciBvZiByZXBvcnRzIGRlY2xpbmVkIHNoYXJwbHkuIFRoaXMgc3VnZ2VzdHMgdGhhdCBVRk8gc2lnaHRpbmdzIG1heSBiZSBpbmZsdWVuY2VkIGJ5IG1lZGlhLCBwdWJsaWMgaW50ZXJlc3QsIG9yIHJlcG9ydGluZyBwcmFjdGljZXMuDQoNCiMjIEFubnVhbCBUcmVuZCBvZiBVRk8gU2lnaHRpbmdzDQoNCmBgYHtyfQ0KdWZvX21vZGVsX2RhdGFfbXV0YXRlZCAlPiUNCiAgbXV0YXRlKHllYXIgPSBsdWJyaWRhdGU6OnllYXIocmVwb3J0ZWRfZGF0ZV90aW1lKSkgJT4lDQogIGNvdW50KHllYXIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gbikpICsNCiAgZ2VvbV9saW5lKGNvbG9yID0gImRhcmtibHVlIikgKw0KICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQiLCBtZXRob2QgPSAibG9lc3MiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQW5udWFsIFRyZW5kIG9mIFVGTyBTaWdodGluZ3MiLA0KICAgIHggPSAiWWVhciIsDQogICAgeSA9ICJOdW1iZXIgb2YgU2lnaHRpbmdzIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQoqKkludGVycHJldGF0aW9uOioqDQoNClRoZSBjaGFydCBzaG93cyBhIGNsZWFyIHJpc2UgaW4gVUZPIHNpZ2h0aW5ncyBmcm9tIHRoZSAxOTgwcyB0byBhcm91bmQgMjAxMiwgd2l0aCBhIHBlYWsgbmVhciAyMDE0LiBBZnRlciB0aGF0LCB0aGVyZeKAmXMgYSBzaGFycCBkZWNsaW5lIGluIHJlcG9ydHMuIFRoZSByZWQgbG9lc3MgY3VydmUgaGlnaGxpZ2h0cyBhIGxvbmctdGVybSB1cHdhcmQgdHJlbmQgZm9sbG93ZWQgYnkgYSByZWNlbnQgZG93bndhcmQgc2hpZnQuIFRoaXMgbWF5IHJlZmxlY3QgY2hhbmdlcyBpbiByZXBvcnRpbmcgYmVoYXZpb3IsIHB1YmxpYyBpbnRlcmVzdCwgb3IgZGF0YSBhdmFpbGFiaWxpdHkgb3ZlciB0aW1lLg0KDQojI051bWJlciBvZiBzaWdodGluZ3MgZGVwZW5kaW5nIG9uIHRoZSBkYXkgb2YgdGhlIHdlZWsNCg0KYGBge3J9DQp1Zm9fbW9kZWxfZGF0YV9tdXRhdGVkICU+JQ0KICBjb3VudCh3ZWVrZGF5KSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gd2Vla2RheSwgeSA9IG4pKSArDQogIGdlb21fY29sKGZpbGwgPSAib3JhbmdlIikgKw0KICBsYWJzKHRpdGxlID0gIlNpZ2h0aW5ncyBkZXBlbmRpbmcgb24gdGhlIGRheSBvZiB0aGUgd2VlayIsIHggPSAiRGF5IG9mIHRoZSB3ZWVrIiwgeSA9ICJOdW1iZXIgb2Ygc2lnaHRpbmdzIikNCmBgYA0KDQoqKkludGVycHJldGF0aW9uOioqDQoNClRoZSBudW1iZXIgb2YgVUZPIHNpZ2h0aW5ncyB2YXJpZXMgYnkgZGF5IG9mIHRoZSB3ZWVrLiBUaGUgaGlnaGVzdCBjb3VudHMgb2NjdXIgb24gU2F0dXJkYXlzIGFuZCBTdW5kYXlzLCB3aGlsZSBUdWVzZGF5cyBoYXZlIHRoZSBmZXdlc3QgcmVwb3J0cy4gVGhpcyBzdWdnZXN0cyBwZW9wbGUgYXJlIG1vcmUgbGlrZWx5IHRvIG5vdGljZSBhbmQgcmVwb3J0IHNpZ2h0aW5ncyBkdXJpbmcgd2Vla2VuZHMsIHBvc3NpYmx5IGR1ZSB0byBoYXZpbmcgbW9yZSBmcmVlIHRpbWUgb3IgYmVpbmcgb3V0ZG9vcnMgbW9yZSBvZnRlbi4NCg0KIyMgSG91cmx5IGRpc3RyaWJ1dGlvbiBvZiBzaWdodGluZ3MNCg0KYGBge3J9DQp1Zm9fbW9kZWxfZGF0YV9tdXRhdGVkICU+JQ0KICBtdXRhdGUoaG91ciA9IGhvdXIocmVwb3J0ZWRfZGF0ZV90aW1lKSkgJT4lDQogIGNvdW50KGhvdXIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBob3VyLCB5ID0gbikpICsNCiAgZ2VvbV9jb2woZmlsbCA9ICJwdXJwbGUiKSArDQogIGxhYnModGl0bGUgPSAiSG91cmx5IGRpc3RyaWJ1dGlvbiBvZiBzaWdodGluZ3MiLCB4ID0gIkhvdXIgb2YgdGhlIGRheSIsIHkgPSAiTnVtYmVyIG9mIHNpZ2h0aW5ncyIpDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbjoqKg0KDQpVRk8gc2lnaHRpbmdzIGFyZSBtb3N0IGZyZXF1ZW50bHkgcmVwb3J0ZWQgYmV0d2VlbiA4IFBNIGFuZCAzIEFNLCBwZWFraW5nIGFyb3VuZCAyIEFNLiBTaWdodGluZ3MgYXJlIGxlYXN0IGNvbW1vbiBkdXJpbmcgbWlkZGF5IGhvdXJzLiBUaGlzIHBhdHRlcm4gc3VnZ2VzdHMgdGhhdCBzaWdodGluZ3MgYXJlIG1vcmUgbGlrZWx5IHRvIG9jY3Vy4oCUb3IgYXQgbGVhc3QgYmUgbm90aWNlZCBhbmQgcmVwb3J0ZWTigJRhdCBuaWdodCwgd2hlbiB0aGUgc2t5IGlzIGRhcmsgYW5kIHVudXN1YWwgbGlnaHRzIGFyZSBtb3JlIHZpc2libGUuDQoNCiMjIEhlYXRtYXA6IGRheSBvZiB0aGUgd2VlayB2cyBob3VyIG9mIHRoZSBkYXkNCg0KYGBge3J9DQp1Zm9fbW9kZWxfZGF0YV9tdXRhdGVkICU+JQ0KICBtdXRhdGUoDQogICAgaG91ciA9IGhvdXIocmVwb3J0ZWRfZGF0ZV90aW1lKSwNCiAgICB3ZWVrZGF5ID0gZmN0X3JlbGV2ZWwod2Vla2RheSwgYygiTW9uIiwgIlR1ZSIsICJXZWQiLCAiVGh1IiwgIkZyaSIsICJTYXQiLCAiU3VuIikpDQogICkgJT4lDQogIGNvdW50KHdlZWtkYXksIGhvdXIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBob3VyLCB5ID0gd2Vla2RheSwgZmlsbCA9IG4pKSArDQogIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArDQogIGxhYnModGl0bGUgPSAiSGVhdG1hcDogZGF5IG9mIHRoZSB3ZWVrIHZzIGhvdXIgb2YgdGhlIGRheSIsIHggPSAiSG91ciBvZiB0aGUgZGF5IiwgeSA9ICJEYXkgb2YgdGhlIHdlZWsiLCBmaWxsID0gIk51bWJlciBvZiBzaWdodGluZ3MiKQ0KDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbjoqKg0KDQpUaGUgaGVhdG1hcCBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIFVGTyBzaWdodGluZ3MgYnkgaG91ciBvZiB0aGUgZGF5IGFuZCBkYXkgb2YgdGhlIHdlZWsuIE1vc3Qgc2lnaHRpbmdzIG9jY3VyIGFmdGVyIG1pZG5pZ2h0IG9uIFN1bmRheSwgcGVha2luZyBiZXR3ZWVuIDHigJMzIEFNLiBPdGhlciBsYXRlLW5pZ2h0IGhvdXJzLCBlc3BlY2lhbGx5IG9uIHdlZWtlbmRzLCBhbHNvIHNob3cgZWxldmF0ZWQgY291bnRzLiBUaGlzIHBhdHRlcm4gcmVpbmZvcmNlcyB0aGF0IHNpZ2h0aW5ncyBhcmUgbW9yZSBmcmVxdWVudCBkdXJpbmcgbGF0ZS1uaWdodCB3ZWVrZW5kIGhvdXJzLCB3aGVuIHBlb3BsZSBhcmUgbGlrZWx5IHRvIGJlIGF3YWtlIGFuZCBvdXRkb29ycyBpbiBkYXJrIGNvbmRpdGlvbnMuDQoNCiMjIFNpZ2h0aW5zIHdpdGggaW1hZ2VzIHZzIG5vIGltYWdlDQoNCmBgYHtyfQ0KdWZvX21vZGVsX2RhdGFfbXV0YXRlZCAlPiUNCiAgbXV0YXRlKGltYWdlX3N0YXR1cyA9IGlmZWxzZShoYXNfaW1hZ2VzLCAiSGFzIGFuIGltYWdlIiwgIkhhcyBubyBpbWFnZSIpKSAlPiUNCiAgY291bnQoaW1hZ2Vfc3RhdHVzKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gIiIsIHkgPSBuLCBmaWxsID0gaW1hZ2Vfc3RhdHVzKSkgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDEpICsNCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpICsNCiAgbGFicyh0aXRsZSA9ICJTaWdodGlucyB3aXRoIGltYWdlcyB2cyBubyBpbWFnZSIsIGZpbGwgPSAiSW1hZ2UgZXhpc3RlbmNlIikgKw0KICB0aGVtZV92b2lkKCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJIYXMgYW4gaW1hZ2UiID0gIiM2NkJCNkEiLCAiSGFzIG5vIGltYWdlIiA9ICIjRUY1MzUwIikpDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbjoqKg0KDQpUaGUgY2hhcnQgc2hvd3MgdGhhdCBhbG1vc3QgYWxsIFVGTyBzaWdodGluZ3MgbGFjayBpbWFnZXMuIFNpZ2h0aW5ncyB3aXRoIGltYWdlcyBhcmUgZXh0cmVtZWx5IHJhcmUsIHN1Z2dlc3RpbmcgdGhhdCByZXBvcnRzIGFyZSB1c3VhbGx5IHRleHQtYmFzZWQgb3IgYW5lY2RvdGFsLiBUaGlzIGluZGljYXRlcyBhIHN0cm9uZyByZWxpYW5jZSBvbiB3aXRuZXNzIHRlc3RpbW9ueSByYXRoZXIgdGhhbiB2aXN1YWwgZXZpZGVuY2UgaW4gdGhlIGRhdGFzZXQuDQoNCk1ha2luZyBzdXJlIGlmIGFib3ZlIHBpZWNoYXJ0IGlzIGNvcnJlY3QNCg0KYGBge3J9DQpzdW0odWZvX21vZGVsX2RhdGFfbXV0YXRlZCRoYXNfaW1hZ2VzICE9IEZBTFNFLCBuYS5ybSA9IFRSVUUpDQpgYGANCg0KIyMgTnVtYmVyIG9mIHNpZ2h0aW5ncyBwZXIgc2hhcGUNCg0KYGBge3J9DQp1Zm9fbW9kZWxfZGF0YV9tdXRhdGVkICU+JQ0KICBjb3VudChzaGFwZSkgJT4lDQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoc2hhcGUsIG4pLCB5ID0gbikpICsNCiAgZ2VvbV9jb2woZmlsbCA9ICJza3libHVlIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBzaWdodGluZ3MgcGVyIHNoYXBlIiwgeCA9ICJTaGFwZSIsIHkgPSAiTnVtYmVyIG9mIHNpZ2h0aW5ncyIpDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbjoqKg0KDQpUaGUgbW9zdCBjb21tb25seSByZXBvcnRlZCBVRk8gc2hhcGVzIGFyZSBsaWdodCwgY2lyY2xlLCBhbmQgdHJpYW5nbGUuIFVudXN1YWwgc2hhcGVzIGxpa2UgY3ViZSwgc3RhciwgYW5kIGNyb3NzIGFyZSB2ZXJ5IHJhcmUuIFRoaXMgc3VnZ2VzdHMgdGhhdCBtb3N0IHNpZ2h0aW5ncyBkZXNjcmliZSBzaW1wbGUgb3IgZ2xvd2luZyBmb3JtcywgcG9zc2libHkgaW5mbHVlbmNlZCBieSB2aXNpYmlsaXR5LCBwZXJjZXB0aW9uLCBvciBjb21tb24gY3VsdHVyYWwgaW1hZ2VyeS4NCg0KIyMgTnVtYmVyIG9mIHNpZ2h0aW5ncyBwZXIgY291bnRyeQ0KDQpgYGB7cn0NCnVmb19tb2RlbF9kYXRhX211dGF0ZWQgJT4lDQogIGNvdW50KGNvdW50cnlfY29kZSkgJT4lDQogIGZpbHRlcihuID49IDEwMCkgJT4lDQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoY291bnRyeV9jb2RlLCBuKSwgeSA9IG4pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTnVtYmVyIG9mIHNpZ2h0aW5ncyBwZXIgY291bnRyeSIsDQogICAgeCA9ICJDb3VudHJ5IGNvZGUiLA0KICAgIHkgPSAiTnVtYmVyIG9mIHNpZ2h0aW5ncyINCiAgKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbjoqKg0KDQpUaGUgdmFzdCBtYWpvcml0eSBvZiBVRk8gc2lnaHRpbmdzIGNvbWUgZnJvbSB0aGUgVW5pdGVkIFN0YXRlcywgd2l0aCBvdmVyIDgwLDAwMCByZXBvcnRzLiBPdGhlciBjb3VudHJpZXMgbGlrZSBDYW5hZGEgYW5kIEdyZWF0IEJyaXRhaW4gaGF2ZSBzaWduaWZpY2FudGx5IGZld2VyIHNpZ2h0aW5ncy4gVGhpcyBzdWdnZXN0cyB0aGF0IHRoZSBkYXRhc2V0IGlzIHN0cm9uZ2x5IFVTLWNlbnRyaWMsIHBvc3NpYmx5IGR1ZSB0byBiZXR0ZXIgcmVwb3J0aW5nIGluZnJhc3RydWN0dXJlLCBwdWJsaWMgaW50ZXJlc3QsIG9yIGRhdGEgc291cmNlIGJpYXMuDQoNCiMjIERlbnNpdHkgbWFwIG9mIHNpZ2h0aW5ncw0KDQpgYGB7cn0NCndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpDQoNCnBsYWNlc19jbGVhbiAlPiUNCiAgZmlsdGVyKCFpcy5uYShsYXRpdHVkZSksICFpcy5uYShsb25naXR1ZGUpKSAlPiUNCiAgbXV0YXRlKA0KICAgIHBvcF9jYXRlZ29yeSA9IGNhc2Vfd2hlbigNCiAgICAgIHBvcHVsYXRpb24gPCAxMDAwMCAgfiAic21hbGwiLA0KICAgICAgcG9wdWxhdGlvbiA8IDEwMDAwMCB+ICJtZWRpdW0iLA0KICAgICAgVFJVRSAgICAgICAgICAgICAgICB+ICJsYXJnZSINCiAgICApDQogICkgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhID0gd29ybGQsIGZpbGwgPSAibGlnaHRncmF5IiwgY29sb3IgPSAiYmxhY2siKSArICAjIERvZGFqZW15IG1hcMSZDQogIGdlb21fcG9pbnQoYWVzKA0KICAgIHggPSBsb25naXR1ZGUsIHkgPSBsYXRpdHVkZSwNCiAgICBzaXplID0gcG9wdWxhdGlvbiwgY29sb3IgPSBwb3BfY2F0ZWdvcnkNCiAgKSwgYWxwaGEgPSAwLjYpICsNCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMSwgNiksIGd1aWRlID0gIm5vbmUiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ2l0aWVzIHdpdGggVUZPIHNpZ2h0aW5ncyIsDQogICAgc3VidGl0bGUgPSAiUG9pbnQgc2l6ZSB+IHBvcHVsYXRpb24sIGNvbG9yIH4gcG9wdWxhdGlvbiBjYXRlZ29yeSIsDQogICAgeCA9ICJMYXRpdHVkZSIsDQogICAgeSA9ICJBbHRpdHVkZSIsDQogICAgY29sb3IgPSAiUG9wdWxhdGlvbiBjYXRlZ29yeSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXRpb246KioNCg0KU2lnaHRpbmdzIGFyZSBtb3N0IGRlbnNlbHkgY2x1c3RlcmVkIGluIE5vcnRoIEFtZXJpY2EgYW5kIEV1cm9wZSwgZXNwZWNpYWxseSBpbiBsYXJnZSB1cmJhbiBhcmVhcy4gVGhpcyBzdWdnZXN0cyB0aGF0IHBvcHVsYXRpb24gZGVuc2l0eSBhbmQgaW5mcmFzdHJ1Y3R1cmUgbWF5IGluZmx1ZW5jZSByZXBvcnRpbmcgZnJlcXVlbmN5LiBPdGhlciByZWdpb25zIHNob3cgZmV3ZXIgcmVwb3J0cywgd2hpY2ggY291bGQgcmVmbGVjdCBsb3dlciByZXBvcnRpbmcgYWNjZXNzIG9yIGxlc3MgZGF0YSBhdmFpbGFiaWxpdHkuDQoNCiMjIFVGTyBTaWdodGluZ3MgYnkgQ2l0eSBQb3B1bGF0aW9uIENhdGVnb3J5DQoNCmBgYHtyfQ0KdWZvX21vZGVsX2RhdGFfbXV0YXRlZCAlPiUNCiAgbGVmdF9qb2luKHBsYWNlc19tb2RlbF9kYXRhX211dGF0ZWQgJT4lIHNlbGVjdChjaXR5X3N0YXRlLCBwb3BfY2F0ZWdvcnkpLCBieSA9ICJjaXR5X3N0YXRlIikgJT4lDQogIGNvdW50KHBvcF9jYXRlZ29yeSkgJT4lDQogIGdncGxvdChhZXMoeCA9IHBvcF9jYXRlZ29yeSwgeSA9IG4sIGZpbGwgPSBwb3BfY2F0ZWdvcnkpKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJVRk8gU2lnaHRpbmdzIGJ5IENpdHkgUG9wdWxhdGlvbiBDYXRlZ29yeSIsDQogICAgeCA9ICJQb3B1bGF0aW9uIENhdGVnb3J5IiwNCiAgICB5ID0gIk51bWJlciBvZiBTaWdodGluZ3MiDQogICkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJzbWFsbCIgPSAiIzkxYmZkYiIsICJtZWRpdW0iID0gIiNmZGFlNjEiLCAibGFyZ2UiID0gIiNkNzMwMjciKSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCioqSW50ZXJwcmV0YXRpb246KioNCg0KVGhlIGNoYXJ0IHNob3dzIHRoYXQgbW9zdCBVRk8gc2lnaHRpbmdzIGNvbWUgZnJvbSBtZWRpdW0tc2l6ZWQgY2l0aWVzLCBmb2xsb3dlZCBieSBsYXJnZSBjaXRpZXMsIHdpdGggc21hbGwgdG93bnMgcmVwb3J0aW5nIHRoZSBmZXdlc3QuIFRoaXMgc3VnZ2VzdHMgdGhhdCBtaWQtc2l6ZWQgdXJiYW4gYXJlYXMgbWF5IG9mZmVyIGEgYmFsYW5jZSBvZiB2aXNpYmlsaXR5LCBvdXRkb29yIGFjdGl2aXR5LCBhbmQgcHVibGljIGVuZ2FnZW1lbnQgY29uZHVjaXZlIHRvIHNpZ2h0aW5ncy4gSXQgYWxzbyByZWZsZWN0cyB3aGVyZSBwZW9wbGUgbGl2ZSBhbmQgYXJlIG1vc3QgbGlrZWx5IHRvIHJlcG9ydCB1bnVzdWFsIGV2ZW50cy4NCg==